﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace Spencen.Mobile.UI.Animations
{
    public class AnimationManager
    {
        private IList<Animation> _animations;
        private Timer _timer;
        private Control _surface; // TODO: No longer required - uses host's Invalidate method
        private object _lock = new object();

        public AnimationManager( Control surface )
        {
            _timer = new Timer();
            _timer.Interval = 50;
            _timer.Tick += new EventHandler( _timer_Tick );
            _surface = surface;
            _animations = new List<Animation>();
        }

        private void _timer_Tick( object sender, EventArgs e )
        {
            StepAnimations();
        }

        private void StepAnimations()
        {
            var expired = new List<Animation>();
            lock ( _lock )
            {
                for ( int index = 0; index < _animations.Count; index++ )
                {
                    var animation = _animations[ index ];
                    if ( !animation.IsStarted )
                        animation.Start();

                    // For UI elements invalidate their display prior to animating - to remove from old bounds.
                    InvalidateTarget( animation );

                    if ( animation.InProgress )
                        animation.Step();

                    if ( animation.IsStarted && !animation.InProgress )
                        expired.Add( animation );

                    // For UI elements invalidate their display post animating - to paint in new bounds.
                    InvalidateTarget( animation );
                }
                //_surface.Invalidate();

                foreach ( var animation in expired )
                    _animations.Remove( animation );
            }

            if ( _animations.Count == 0 )
                _timer.Enabled = false;
            else
                _timer.Enabled = true;
        }

        private static void InvalidateTarget( Animation animation )
        {
            var drawingTarget = animation.Target as DrawingElement;
            if ( drawingTarget != null )
                drawingTarget.Invalidate();
        }

        public void AddAnimation( Animation newAnimation )
        {
            AddAnimation( newAnimation, false );
        }

        public void AddAnimation(Animation newAnimation, bool immediate)
        {
            // Remove any existing animation of the same type that has been registered for this object.
            // This is useful when a move animation is overridden for example.
            var oldAnimation = _animations
                .Where( a => a.Target == newAnimation.Target && a.TargetProperty == newAnimation.TargetProperty )
                .FirstOrDefault();
            if ( oldAnimation != null )
                _animations.Remove( oldAnimation );
            
            _animations.Add( newAnimation);
            if ( immediate )
                StepAnimations();
            else
                _timer.Enabled = true;
        }

        public void ClearAllAnimations()
        {
            _timer.Enabled = false;
            lock ( _lock )
            {
                _animations.Clear();
            }
        }
    }
}
